package view;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Observable;
import java.util.Observer;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;

import model.Database;
import model.Evento;
import model.SearchEvent;
import controller.ActionHomeCalendar;
import controller.HomeCalendarObserver;

@SuppressWarnings("serial")
public class HomeCalendar extends JPanel implements Observer {
	public static int dd, yy, mm;
	public static String day = "", month = "", year = "", thisdd = "",
			thismm = "", thisyy = "";
	private static JButton labs[][];
	JButton plusYear;
	JButton minusYear;
	JButton plusMonth;
	JButton minusMonth;
	private static int gapDay = 0;
	public static Calendar calendar = new GregorianCalendar();
	public static int thisYear = calendar.get(Calendar.YEAR);
	public static int thisMonth = calendar.get(Calendar.MONTH);
	public static int thisday = calendar.get(Calendar.DAY_OF_MONTH);
	public static JPanel calendario;
	private static JPanel tp;
	private static JPanel bp;
	public static JComboBox<String> monthChoice;
	public static JComboBox<String> yearChoice;
	private static ActionListener dateSetter = new ActionHomeCalendar();
	static Dimension DimDay = new Dimension(50, 20);

	public HomeCalendar() {
		new HomeCalendarObserver();
		setYYMMDD();
		startHomeCalendar();
		if (HomeCalendarObserver.obs.countObservers() != 0)
			HomeCalendarObserver.obs.deleteObservers();
		HomeCalendarObserver.obs.addObserver(this);
	}

	private void setYYMMDD() {
		yy = thisYear;
		mm = thisMonth;
		dd = thisday;
		if (dd < 10)
			thisdd = "0" + String.valueOf(dd);
		else
			thisdd = String.valueOf(dd);
		if ((mm + 1) < 10)
			thismm = "0" + String.valueOf((mm + 1));
		else
			thismm = String.valueOf((mm + 1));
		thisyy = String.valueOf(yy);
	}

	static String[] months = { "Gennaio", "Febbrio", "Marzo", "Aprile",
		"Maggio", "Giugno", "Luglio", "Agosto", "Settembre", "Ottobre",
		"Novembre", "Dicembre" };

	static String[] giorno = { "lunedì", "martedì", "mercoledì", "giovedì",
		"venerdì", "sabato", "domenica" };

	/** Build the GUI. Assumes that setYYMMDD has been called. */
	public void startHomeCalendar() {

		calendario = new JPanel();
		calendario = this;
		calendario.setBackground(Color.white);

		// setto la data come stringa
		if (dd < 10)
			day = "0" + String.valueOf(dd);
		else
			day = String.valueOf(dd);
		if ((mm + 1) < 10)
			month = "0" + String.valueOf((mm + 1));
		else
			month = String.valueOf((mm + 1));
		year = String.valueOf(yy);

		tp = new JPanel();
		tp.setBackground(Color.white);

		tp.setAlignmentX(CENTER_ALIGNMENT);
		tp.setAlignmentY(CENTER_ALIGNMENT);

		JButton Lunedì = new JButton("Lunedì");
		JButton Martedì = new JButton("Martedì");
		JButton Mercoledì = new JButton("Mercoledì");
		JButton Giovedì = new JButton("Giovedì");
		JButton Venerdì = new JButton("Venerdì");
		JButton Sabato = new JButton("Sabato");
		JButton Domenica = new JButton("Domenica");

		Lunedì.setMinimumSize(DimDay);
		Lunedì.setPreferredSize(DimDay);
		Lunedì.setMaximumSize(DimDay);
		Martedì.setMinimumSize(DimDay);
		Martedì.setPreferredSize(DimDay);
		Martedì.setMaximumSize(DimDay);
		Mercoledì.setMinimumSize(DimDay);
		Mercoledì.setPreferredSize(DimDay);
		Mercoledì.setMaximumSize(DimDay);
		Giovedì.setMinimumSize(DimDay);
		Giovedì.setPreferredSize(DimDay);
		Giovedì.setMaximumSize(DimDay);
		Venerdì.setMinimumSize(DimDay);
		Venerdì.setPreferredSize(DimDay);
		Venerdì.setMaximumSize(DimDay);
		Sabato.setMinimumSize(DimDay);
		Sabato.setPreferredSize(DimDay);
		Sabato.setMaximumSize(DimDay);
		Domenica.setMinimumSize(DimDay);
		Domenica.setPreferredSize(DimDay);
		Domenica.setMaximumSize(DimDay);

		plusYear = new JButton(">>");
		plusMonth = new JButton(">");
		minusYear = new JButton("<<");
		minusMonth = new JButton("<");
		plusMonth.addActionListener(dateSetter);
		minusMonth.addActionListener(dateSetter);
		plusYear.addActionListener(dateSetter);
		minusYear.addActionListener(dateSetter);
		plusYear.setName("plusYear");
		plusMonth.setName("plusMonth");
		minusYear.setName("minusYear");
		minusMonth.setName("minusMonth");

		tp.add(minusYear);
		tp.add(minusMonth);
		tp.add(monthChoice = new JComboBox<String>());
		for (int i = 0; i < months.length; i++)
			monthChoice.addItem(months[i]);
		monthChoice.setSelectedItem(months[mm]);
		monthChoice.setName("monthChoice");
		monthChoice.addActionListener(dateSetter);

		tp.add(yearChoice = new JComboBox<String>());
		yearChoice.setEditable(true);
		for (int i = thisYear - 50; i < thisYear + 15; i++)
			yearChoice.addItem(Integer.toString(i));
		yearChoice.setSelectedItem(Integer.toString(yy));
		yearChoice.addActionListener(dateSetter);
		yearChoice.setName("yearChoice");

		tp.add(plusMonth);
		tp.add(plusYear);

		// tp.setMaximumSize(new Dimension(300,50));

		bp = new JPanel();
		bp.setBackground(Color.white);
		bp.setLayout(new GridLayout(7, 7));
		labs = new JButton[6][7]; // first row is days

		bp.add(Lunedì);
		bp.add(Martedì);
		bp.add(Mercoledì);
		bp.add(Giovedì);
		bp.add(Venerdì);
		bp.add(Sabato);
		bp.add(Domenica);

		for (int i = 0; i < bp.getComponentCount(); i++) {
			bp.getComponent(i).setFocusable(false);
			((JButton) bp.getComponent(i)).setContentAreaFilled(false);
			((JButton) bp.getComponent(i)).setBounds(new Rectangle(93, 43));
		}

		// Construct all the buttons, and add them.
		for (int i = 0; i < 6; i++)
			for (int j = 0; j < 7; j++) {
				bp.add(labs[i][j] = new JButton());
				labs[i][j].addActionListener(dateSetter);
				labs[i][j].setFocusable(true);
				labs[i][j].setBounds(new Rectangle(93, 43));
				labs[i][j].setName("dayChoice");
				labs[i][j].setActionCommand("");
				labs[i][j].setMargin(new Insets(-6, 0, 4, 0));
				labs[i][j].setBackground(new Color(185, 220, 255, 255));
				labs[i][j].setEnabled(false);
			}

		// System.out.println("Cal::recompute: " + yy + ":" + mm + ":" + dd);
		if (mm < 0 || mm > 11)
			throw new IllegalArgumentException("Month " + mm
					+ " deve essere compreso tra 0-11");
		// clearDayActive();
		calendar = new GregorianCalendar(yy, mm, dd);

		// Recupero il primo giorno della settimana
		// getDay() restituisce 0 per la domenica,dato che il calendario è
		// italiano sposto la domenica al 6.
		gapDay = new GregorianCalendar(yy, mm, 1).get(Calendar.DAY_OF_WEEK) - 2;
		if (gapDay == -1)
			gapDay = 6;
		//System.out.println("leadGap = " + gapDay + " giorno = "+ giorno[gapDay]);

		int daysInMonth = dom[mm];
		if (isLeap(calendar.get(Calendar.YEAR)) && mm == 1)
			// if (isLeap(calendar.get(Calendar.YEAR)) && mm > 1)
			++daysInMonth;

		// Fill in numbers for the day of month.
		for (int i = 1; i <= daysInMonth; i++) {
			JButton b = labs[(gapDay + i - 1) / 7][(gapDay + i - 1) % 7];
			b.setActionCommand(Integer.toString(i));
			setEvent((gapDay + i - 1) / 7, (gapDay + i - 1) % 7);
		}

		// 7 days/week * up to 6 rows
		for (int i = gapDay + 1 + daysInMonth; i < 6 * 7; i++)
			labs[i / 7][i % 7].setActionCommand("");

		// setta il giorno odierno
		if (yy != thisYear || mm != thisMonth)
			clearCurrentDay();
		else
			setCurrentDay();

		tp.setMinimumSize(new Dimension(651, 40));
		tp.setPreferredSize(new Dimension(651, 40));
		tp.setMaximumSize(new Dimension(651, 40));

		bp.setMinimumSize(new Dimension(651, 259));
		bp.setPreferredSize(new Dimension(651, 259));
		bp.setMaximumSize(new Dimension(651, 259));

		calendario.setLayout(new BoxLayout(calendario, BoxLayout.Y_AXIS));
		calendario.add(tp);
		calendario.add(bp);
		calendario.setMinimumSize(new Dimension(651, 301));
		calendario.setPreferredSize(new Dimension(651, 301));
		calendario.setMaximumSize(new Dimension(651, 301));
	}

	public final static int dom[] = { 31, 28, 31, 30, /* jan feb mar apr */
		31, 30, 31, 31, /* may jun jul aug */
		30, 31, 30, 31 /* sep oct nov dec */
	};

	/**
	 * isLeap() restituise vero se l'anno è bisestile
	 * 
	 * "a year is a leap year if it is divisible by 4 but not by 100, except
	 * that years divisible by 400 *are* leap years." -- Kernighan & Ritchie,
	 * _The C Programming Language_, p 37.
	 */
	public static boolean isLeap(int year) {
		if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
			return true;
		return false;
	}

	private static int activeDay = -1;

	private static void clearDayActive() {
		JButton b;
		// First un-shade the previously-selected square, if any
		if (activeDay > 0) {
			b = labs[(gapDay + activeDay - 1) / 7][(gapDay + activeDay - 1) % 7];
			b.repaint();
			activeDay = -1;
		}
	}

	public static void setDayActive(int newDay) {
		clearDayActive();
		// Set the new one
		if (newDay <= 0)
			dd = new GregorianCalendar().get(Calendar.DAY_OF_MONTH);
		else
			dd = newDay;
		if (dd < 10)
			day = "0" + String.valueOf(dd);
		else
			day = String.valueOf(dd);
		if ((mm + 1) < 10)
			month = "0" + String.valueOf((mm + 1));
		else
			month = String.valueOf((mm + 1));
		year = String.valueOf(yy);
		Component square = labs[(gapDay + newDay - 1) / 7][(gapDay + newDay - 1) % 7];
		square.repaint();
		activeDay = newDay;
	}

	static Color colore;
	public static void setCurrentDay() {
		dd = new GregorianCalendar().get(Calendar.DAY_OF_MONTH);
		colore = labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].getBackground();
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setFocusable(true);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setFocusPainted(true);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].repaint();
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setForeground(Color.white);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setBackground(Color.green);
	}

	private static void clearCurrentDay() {
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setFocusable(false);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setFocusPainted(false);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].repaint();
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setBackground(colore);
		labs[(gapDay + dd - 1) / 7][(gapDay + dd - 1) % 7].setForeground(Color.black);
	}

	public static void setEvent(int i,int j){
		if (!labs[i][j].getActionCommand().contentEquals("")){
			labs[i][j].setEnabled(true);
			String giorno = labs[i][j].getActionCommand();
			if (Integer.valueOf(giorno)<10)
				giorno = "0"+giorno;
			//System.out.println(giorno+month+year);

			//i mesi iniziano da 0 dunque bisogna aggiungere 1
			int level;
			if (Database.Utente.getLevel() == 512){
				level = SearchEvent.getAdminLevelEventOfDate(giorno, month, year);
				labs[i][j].add(setEventSign(SearchEvent.getAdminVectEventOfDate(giorno, month, year),i,j));
			}
			else{
				level = SearchEvent.getLevelEventOfDate(giorno, month, year);
				labs[i][j].add(setEventSign(SearchEvent.getVectEventOfDate(giorno, month, year),i,j));
			}
			switch (level){
			case 0:{
				labs[i][j].setBackground(new Color(39,121,222,30));
				break;
			}
			case 1:{
				labs[i][j].setBackground(new Color(243,91,18,30));
				break;
			}
			default:labs[i][j].setBackground(new Color(185,220,255));
			}

		}
	}

	private static JPanel setEventSign(Vector<Evento> evn, int i, int j) {
		JPanel container = new JPanel();
		JPanel eventSignContainer = new JPanel();

		int heightLabs = labs[i][j].getHeight();
		int widthLabs = labs[i][j].getWidth();
		int contEvn = evn.size();

		container.setFocusable(false);
		container.setBackground(new Color(0, 0, 0, 0));
		eventSignContainer.setFocusable(true);
		eventSignContainer.setBackground(new Color(0, 0, 0, 0));
		eventSignContainer.setLayout(new GridLayout(1, contEvn));
		if (contEvn != 0) {
			int effettiva = (widthLabs / contEvn) - contEvn - 1;
			for (int x = 0; x < contEvn; x++) {
				JPanel eventSign = new JPanel();
				eventSign.setMinimumSize(new Dimension(1, 3));
				eventSign.setMaximumSize(new Dimension(effettiva, 3));
				eventSign.setPreferredSize(new Dimension(effettiva, 3));
				eventSign.setBackground(setColorEventSign(evn.get(x)));
				eventSignContainer.add(eventSign);
				if (x != contEvn - 1) {
					JPanel spaceSign = new JPanel();
					spaceSign.setMinimumSize(new Dimension(1, 3));
					spaceSign.setMaximumSize(new Dimension(1, 3));
					spaceSign.setPreferredSize(new Dimension(1, 3));
					spaceSign.setBackground(new Color(0, 0, 0, 0));
					eventSignContainer.add(spaceSign);
				}

			}
		} else {
			JPanel noSign = new JPanel();
			noSign.setMinimumSize(new Dimension(widthLabs, 3));
			noSign.setMaximumSize(new Dimension(widthLabs, 3));
			noSign.setPreferredSize(new Dimension(widthLabs, 3));
			noSign.setBackground(new Color(0, 0, 0, 0));
			eventSignContainer.add(noSign);
		}

		JPanel data_panel = new JPanel();
		JLabel data = new JLabel(labs[i][j].getActionCommand());
		data_panel.add(data);
		data_panel.setMaximumSize(new Dimension(widthLabs - 20, heightLabs));
		data_panel.setBackground(new Color(0, 0, 0, 0));

		container.setLayout(new BoxLayout(container, BoxLayout.Y_AXIS));
		container.add(data_panel);
		container.add(eventSignContainer);
		// container.add(Box.createVerticalGlue());
		return container;
	}

	private static Color setColorEventSign(Evento ev) {
		switch (ev.getType()) {
		case "Altro":
			return new Color(200, 20, 0);
		case "Relazione":
			return new Color(70, 240, 200);
		case "Incontro":
			return new Color(20, 120, 20);
		case "Team building":
			return new Color(250, 180, 0);
		case "Riunione":
			return new Color(200, 50, 200);
		default:
			return new Color(255, 255, 255);
		}

	}

	@Override
	public void update(Observable o, Object arg) {
		calendario.removeAll();
		startHomeCalendar();
		calendario.repaint();
		calendario.validate();
	}
}